package com.naiterui.ehp.bs.pharmacist.service.impl;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.naiterui.common.redis.RedisUtil;
import com.naiterui.ehp.bp.bo.esign.EsignDoctorBO;
import com.naiterui.ehp.bp.bo.pharmacist.PharmacistInfoBO;
import com.naiterui.ehp.bp.constants.CommonConstant;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.support.utils.JsonMapper;
import com.naiterui.ehp.bp.utils.lang.ConfigUtil;
import com.naiterui.ehp.bp.utils.thread.ThreadPoolUtil;
import com.naiterui.ehp.bs.pharmacist.entity.Pharmacist;
import com.naiterui.ehp.bs.pharmacist.exception.ExceptionCodes;
import com.naiterui.ehp.bs.pharmacist.feign.PharmacistEsignFeignClient;
import com.naiterui.ehp.bs.pharmacist.repository.mysql.DrLicenceRepository;
import com.naiterui.ehp.bs.pharmacist.repository.mysql.PharmacistRepository;
import com.naiterui.ehp.bs.pharmacist.service.IPharmacistService;
import com.naiterui.ehp.bs.pharmacist.utils.Constants;
import com.naiterui.ehp.bs.pharmacist.vo.recommend.PharmacistVO;
import com.naiterui.ehp.bs.pharmacist.vo.user.PharmacistParamVO;
import com.naiterui.ehp.bs.pharmacist.vo.user.SignUserParamVO;

import cn.hutool.core.util.IdcardUtil;

/**
 * @author guoyongxiang
 * @date 2019/12/4 22:15
 * @since 1.0.0
 */
@Service
public class PharmacistPharmacistServiceImpl implements IPharmacistService {

    private static final Logger LOGGER = LoggerFactory.getLogger(PharmacistPharmacistServiceImpl.class);

    private final static String RDS_LAST_AUDIT_PHARMACIST = CommonConstant.REDIS_PRE_PHARMACIST + "last_audit_ph";

    private final static Integer GENDER_MALE = 1;
    private final static Integer GENDER_FEMALE = 2;
    @Value("${ehp.domain.img}")
    private String imgDomain;

    @Autowired
    private PharmacistRepository pharmacistRepository;
    @Autowired
    private DrLicenceRepository licencyRepository;
    @Value("${file.base.prefix}")
    private String fileBasePre;
    @Autowired
    private PharmacistEsignFeignClient pharmacistEsignFeignClient;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void userAuth(Long userId, Integer status, String reason) throws BusinessException {
        Pharmacist pharmacist = pharmacistRepository.get(userId);
        if (pharmacist == null) {
            LOGGER.warn("药师用户不存在 id:{}", userId);
            throw new BusinessException(ExceptionCodes.PHARMACIST_ACCOUNT_NOT_EXISTS);
        }
        //实名通过，则表示该药师账号已激活(无app时，没有账户激活逻辑)
        pharmacist.setStatus(Pharmacist.STATUS_ACTIVE);
        pharmacist.setAuthStatus(status);
        pharmacist.setChangedAt(new Date());
        pharmacist.setChangedBy("CA");
        pharmacistRepository.update(pharmacist);

        if (RedisUtil.keyOps().existsKey(CommonConstant.SUPERVISE_SYNCHRONIZE_KEY)) {
            // 异步处理
            ThreadPoolUtil.execute(() -> {
                // 如果认证成功，药师信息同步至监管
                if (status.equals(Pharmacist.AUTH_STATUS_PASS)) {
                    RedisUtil.listOps().lpush(CommonConstant.SUPERVISE_PUSH_PHARMACIST_LIST_KEY, userId + "");
                }
            });
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Pharmacist update(String operator, PharmacistParamVO paramVO) throws BusinessException {
        // 查询账户
        Pharmacist pharmacist = pharmacistRepository.get(paramVO.getId());
        if (pharmacist == null) {
            LOGGER.warn("药师用户不存在 id:{}", paramVO.getId());
            throw new BusinessException(ExceptionCodes.PHARMACIST_ACCOUNT_NOT_EXISTS);
        }
        Pharmacist firstByPhoneOrCardNo =
            pharmacistRepository.findFirstByPhoneOrCardNo(paramVO.getPhone(), paramVO.getCardNo());
        LOGGER.info("pharmacist update pharmacist: {}", JsonMapper.toJson(firstByPhoneOrCardNo));
        if (null != firstByPhoneOrCardNo) {
            // 手机号重复
            if (!paramVO.getId().equals(firstByPhoneOrCardNo.getId())
                && paramVO.getPhone().equals(firstByPhoneOrCardNo.getPhone())) {
                throw new BusinessException(ExceptionCodes.PHARMACIST_PHONE_IS_EXISTS);
            }
            // 身份证号重复
            if (!paramVO.getId().equals(firstByPhoneOrCardNo.getId())
                && paramVO.getCardNo().equals(firstByPhoneOrCardNo.getCardNo())) {
                throw new BusinessException(ExceptionCodes.PHARMACIST_ID_CARD_IS_EXISTS);
            }
        }
        if (!Pharmacist.AUTH_STATUS_PASS.equals(pharmacist.getAuthStatus())) {
            //已认证状态不能修改身份证和姓名
            pharmacist.setName(paramVO.getName());
            String cardNo = paramVO.getCardNo();
            if (StringUtils.isNotBlank(cardNo)) {
                Integer gender = 0;
                if (Integer.parseInt(cardNo.substring(16).substring(0, 1)) % 2 == 0) {
                    gender = GENDER_FEMALE;
                } else {
                    gender = GENDER_MALE;
                }
                pharmacist.setGender(gender);
                pharmacist.setCardNo(cardNo);
            }
        }

        pharmacist.setPhone(paramVO.getPhone());
        pharmacist.setEthnicity(paramVO.getEthnicity());
        pharmacist.setLicenseNo(paramVO.getLicenseNo());

        String licenseUrl = paramVO.getLicenseUrl().replaceAll(imgDomain, "");
        pharmacist.setLicenseUrl(licenseUrl);

        pharmacist.setLicenseDate(paramVO.getLicenseDate());
        if (StringUtils.isNotBlank(paramVO.getSealImage())) {
            pharmacist.setSealImage(paramVO.getSealImage().replaceAll(ConfigUtil.getString("ehp.domain.img"), ""));
        }
        pharmacist.setSkill(paramVO.getSkill());
        //pharmacist.setAuthStatus(Pharmacist.AUTH_STATUS_PENDING);
        pharmacist.setChangedAt(new Date());
        pharmacist.setChangedBy(operator);
        pharmacist.setTitleId(paramVO.getTitleId());
        if(StringUtils.isNotBlank(paramVO.getFrontUrl())){
            pharmacist.setFrontUrl(paramVO.getFrontUrl().replaceAll(ConfigUtil.getString("ehp.domain.img"), ""));
        }
        if(StringUtils.isNotBlank(paramVO.getBackUrl())){
            pharmacist.setBackUrl(paramVO.getBackUrl().replaceAll(ConfigUtil.getString("ehp.domain.img"), ""));
        }
        pharmacistRepository.update(pharmacist);
        return pharmacist;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Pharmacist add(String operator, PharmacistParamVO paramVO) throws BusinessException {
        String phone = paramVO.getPhone();
        String cardNo = paramVO.getCardNo();
        LOGGER.info("pharmacist add phone: {}, cardNo: {}", phone, cardNo);
        Pharmacist pharmacist = pharmacistRepository.findFirstByPhoneOrCardNo(phone, cardNo);
        LOGGER.info("pharmacist add pharmacist: {}", JsonMapper.toJson(pharmacist));
        if (null != pharmacist) {
            // 手机号重复
            if (phone.equals(pharmacist.getPhone())) {
                throw new BusinessException(ExceptionCodes.PHARMACIST_PHONE_IS_EXISTS);
            }
            // 身份证号重复
            if (cardNo.equals(pharmacist.getCardNo())) {
                throw new BusinessException(ExceptionCodes.PHARMACIST_ID_CARD_IS_EXISTS);
            }
        }

        EsignDoctorBO doctorBO = this.pharmacistEsignFeignClient.getDrAccountByIdNoAndAuthStatus(cardNo, EsignDoctorBO.AUTH_STATUS_PASS);
        if(doctorBO != null){
            LOGGER.warn("此身份证号已有医生注册并通过实名 number:{}", cardNo);
            throw new BusinessException(ExceptionCodes.PHARMACIST_DOCTOR_ID_CARD_IS_EXISTS);
        }
        Integer gender;
        if (IdcardUtil.getGenderByIdCard(cardNo) == 1) {
            gender = GENDER_MALE;
        } else {
            gender = GENDER_FEMALE;
        }
//        Integer idCardNum = licencyRepository.countByTypeAndNumber(DrLicence.DOCTOR_LICENCE_TYPE_IDCARD, cardNo);
//        if (idCardNum != null && idCardNum > 0) {
//            LOGGER.warn("此身份证号已有医生注册 number:{}", cardNo);
//            throw new BusinessException(ExceptionCodes.PHARMACIST_DOCTOR_ID_CARD_IS_EXISTS);
//        }
        // 执业药师资格证
        String licenseUrl = paramVO.getLicenseUrl() != null ? paramVO.getLicenseUrl().replaceAll(imgDomain, "") : "";
        // 身份证正面照
        String frontUrl = paramVO.getFrontUrl() != null ? paramVO.getFrontUrl().replaceAll(imgDomain, "") : "";
        // 身份证反面照
        String backUrl = paramVO.getBackUrl() != null ? paramVO.getBackUrl().replaceAll(imgDomain, "") : "";
        pharmacist = Pharmacist.builder()
            .name(paramVO.getName())
            .phone(phone).cardNo(cardNo)
            .gender(gender)
            .authStatus(Pharmacist.AUTH_STATUS_PENDING)
            .accountStatus(Pharmacist.ACCOUNT_STATUS_NORMAL)
            .status(Pharmacist.STATUS_NOT_ACTIVE)
            .titleId(paramVO.getTitleId())
            .ethnicity(paramVO.getEthnicity())
            .skill(paramVO.getSkill())
            .licenseNo(paramVO.getLicenseNo())
                                          .licenseUrl(licenseUrl)
                                          .licenseDate(paramVO.getLicenseDate())
                                          .sealImage(paramVO.getSealImage())
                                          .createdAt(new Date())
                                          .createdBy(operator)
                                          .changedAt(new Date())
                                          .changedBy(operator)
                                          .frontUrl(frontUrl)
                                          .backUrl(backUrl)
                                          .build();
        pharmacistRepository.save(pharmacist);
        return pharmacist;
    }

    @Override
    public List<PharmacistVO> getAuditPharmacist(Integer count) throws BusinessException {
        //count = Optional.ofNullable(count).orElse(1);
        //Long lastPhId = (Long) RedisUtil.valueOps().getObject(RDS_LAST_AUDIT_PHARMACIST);

        // 请求数量大于可用药师
        List<Pharmacist> ids = pharmacistRepository.findAllByStatusAndAuthStatusAndAccountStatus(Pharmacist.STATUS_ACTIVE, Pharmacist.AUTH_STATUS_PASS, Pharmacist.ACCOUNT_STATUS_NORMAL);
        if (ids == null || ids.size() < 1) {
            LOGGER.warn("暂无可用激活药师");
            throw new BusinessException(ExceptionCodes.PHARMACIST_ACCOUNT_NOT_EXISTS, "暂无可用激活药师");
        }
        return ids.stream().map(p -> PharmacistVO.builder().id(p.getId()).name(p.getName()).build()).collect(Collectors.toList());


        /*lastPhId = Optional.ofNullable(lastPhId).orElse(ids.get(0).getId());
        List<PharmacistVO> auditPhIds = new ArrayList<>();
        for (long i = lastPhId; i < count + lastPhId; i++) {
            Integer index = (int) (i + 1) % ids.size();
            Pharmacist pharmacist = ids.get(index);
            auditPhIds.add(PharmacistVO.builder().id(pharmacist.getId()).name(pharmacist.getName()).build());
        }
        int lastIndex = auditPhIds.size() - 1;
        lastPhId = auditPhIds.get(lastIndex).getId();
        RedisUtil.valueOps().set(RDS_LAST_AUDIT_PHARMACIST, lastPhId);
        return auditPhIds;*/
    }


    @Override
    public PharmacistInfoBO getPharmacistInfo(Long pharmacistId) {
        LOGGER.info("获取处方关联药师：pharmacistId={}", pharmacistId);
        Pharmacist pharmacist = pharmacistRepository.get(pharmacistId);
        return PharmacistInfoBO.builder()
                               .id(pharmacist.getId())
                               .name(pharmacist.getName())
                               .sealImage(ConfigUtil.getString("img.hosts") + pharmacist.getSealImage())
                               .build();
    }

    @Override
    public void perfectSealImage(String sealImage, Long pharmacistId) throws BusinessException {
        Pharmacist pharmacist = pharmacistRepository.get(pharmacistId);
        pharmacist.setSealImage(sealImage);
        pharmacist.setChangedAt(new Date());
        pharmacistRepository.update(pharmacist);
    }

    @Override
    public List<PharmacistInfoBO> getPharmacistInfoList(List<Long> pharmacistIds) {
        List<Pharmacist> pharmacists = pharmacistRepository.findByIdIn(pharmacistIds);
        List<PharmacistInfoBO> result = new ArrayList<>();
        pharmacists.forEach(pharmacist -> {
            result.add(PharmacistInfoBO.builder().id(pharmacist.getId()).name(pharmacist.getName())
                .sealImage(ConfigUtil.getString("img.hosts") + pharmacist.getSealImage())
                .licenseNo(pharmacist.getLicenseNo()).idCard(pharmacist.getCardNo()).build());
        });
        return result;
    }

    /**
     * 修改药师禁用状态 0正常  1禁用
     * @param pharmacistId
     * @param status
     * @param operator
     */
    @Override
    public void updateAccountStatus(Long pharmacistId, Integer status, String operator) {
        Pharmacist pharmacist = pharmacistRepository.get(pharmacistId);
        pharmacist.setAccountStatus(status);
        pharmacist.setChangedAt(new Date());
        pharmacistRepository.update(pharmacist);
    }

    @Override
    public String saveSealImg(Long pharmacistId, MultipartFile sealImg) throws BusinessException {
        Pharmacist pharmacist = pharmacistRepository.get(pharmacistId);
        if (null == pharmacist) {
            throw new BusinessException(ExceptionCodes.USER_NOT_EXIST);
        }
        // 保存签章图
        if (sealImg != null) {
            LOGGER.info("上传医生签名图片 pharmacistId:{}, fileName:{}", pharmacistId, sealImg.getName());
            // 生成签名印章
            String filepath = Constants.SEAL_PATH_PRE_PH + pharmacistId + "_" + System.currentTimeMillis() + "_o.jpg";
            LOGGER.info("上传医生签名图片地址 {}", filepath);
            File signImgfile = new File(filepath);
            try {
                FileUtils.forceMkdirParent(signImgfile);
                FileUtils.copyInputStreamToFile(sealImg.getInputStream(), signImgfile);
            } catch (IOException e) {
                throw new BusinessException(ExceptionCodes.PHARMACIST_SEAL_IMG_FAIL);
            }
            String path = filepath.replaceAll(this.fileBasePre, "");
            LOGGER.info("替换路径前缀后地址 {}", filepath);
            pharmacist.setSealImage(path);
            pharmacist.setChangedAt(new Date());
            pharmacistRepository.update(pharmacist);

            // 电签用户签章图信息修改p
            pharmacistEsignFeignClient.saveSealImg(pharmacistId, path);
            return StringUtils.isNotEmpty(pharmacist.getSealImage()) ? imgDomain + pharmacist.getSealImage() : "";
        }
        return null;
    }

    @Override
    public SignUserParamVO getUserByPhone(String phone) throws BusinessException {
        Pharmacist pharmacist = pharmacistRepository.findFirstByPhone(phone);
        if (null == pharmacist) {
            throw new BusinessException(ExceptionCodes.USER_NOT_EXIST);
        }
        return SignUserParamVO.builder().userId(pharmacist.getId()).phone(phone).idCard(pharmacist.getCardNo())
            .name(pharmacist.getName()).sealImagePath(pharmacist.getSealImage()).build();
    }
}
